home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 May / macpower199705.bin / AMUG / PROGRAMMING / BoxMaker++ 1.5.sit / BoxMaker++ 1.5 / Pixelize ƒ / pixelize.cp / pixelize.cp
Encoding:
Text File  |  1996-11-30  |  15.1 KB  |  634 lines  |  [TEXT/KAHL]

  1. #include <assert.h>
  2.  
  3. #include <fstream.h>
  4. #include <strstream.h>
  5.  
  6. #include <Types.h>
  7. #include <Memory.h>
  8. #include <QuickDraw.h>
  9. #include <OSUtils.h>
  10. #include <ToolUtils.h>
  11. #include <Menus.h>
  12. #include <Packages.h>
  13. #include <Traps.h>
  14. #include <Files.h>
  15. #include <Aliases.h>
  16. #include <AppleEvents.h>
  17. #include <GestaltEqu.h>
  18. #include <Processes.h>
  19. #include <Fonts.h>
  20. #include <OSEvents.h>
  21. #include <Resources.h>
  22. #include <Desk.h>
  23.  
  24. #include <Windows.h>
  25. #include <QDOffscreen.h>
  26. #include <SegLoad.h>
  27. #include <TextEdit.h>
  28. #include <Folders.h>
  29.  
  30. #include <PictUtils.h>
  31.  
  32. #include "gestalt_.h"
  33. #include "gworld.h"
  34.  
  35. #include "fsspec.h"
  36. #include "access_path.h"
  37. #include "standardfile_.h"
  38. #include "standardgetfile.h"
  39. #include "boxmakergetfile.h"
  40.  
  41. #include "handle.h"
  42. #include "resource.h"
  43.  
  44. #include "picture.h"
  45.  
  46. #include "resourcefile.h"
  47.  
  48. #include "boxmaker constants.h"
  49. #include "boxmaker.h"
  50.  
  51. #include "preferences.cp"
  52. #include "pixelize.h"
  53.  
  54. #pragma template_access public
  55.  
  56. void main();
  57.  
  58. const short real_modes[ 16] =
  59. {
  60.     srcCopy,        srcOr,            srcXor,            srcBic,
  61.     notSrcCopy,        notSrcOr,        notSrcXor,        notSrcBic,
  62.     blend,            addPin,            addOver,        subPin,
  63.     addMax,            adMax,            subOver,        adMin
  64. };
  65.  
  66. void main()
  67. {
  68.     pixelize_settings defaultsettings =
  69.     {
  70.         iBlackAndWhite,
  71.         iPictFile,
  72.         useSystemDefault,
  73.         false,                // dontCountPixels
  74.         false,                // dont suppress Black and White
  75.         false,                // not transparent
  76.         true,                // do dither
  77.         0                    // srcCopy
  78.     };
  79.     stringhandle prefsFileHandle( 128);
  80.  
  81.     pixelize_shell it( *(Str63 *)*(Handle)prefsFileHandle, defaultsettings);
  82.     it.run();
  83. }
  84.  
  85. pixelize_shell::pixelize_shell(
  86.     Str31 prefsFileName, pixelize_settings &defaultsettings)
  87.     : boxmaker( 3000)
  88.     , pixelize_prefs( prefsFileName, defaultsettings)
  89. {
  90.     folder_depth = 0;
  91.  
  92.     ChangeDepth( whichDepth);
  93.     ChangeStorage( whichStorage);
  94.     ChangeSampling( whichSampling);
  95.     ChangeMode( whichTransfermode);
  96.  
  97.     SetAButton( iCountPixels, countPixels);
  98.     SetAButton( iAlwaysAddBW, alwaysAddBW);
  99.     SetAButton( iTransparent, makeTransparent);
  100.     SetAButton( iDither, dither);
  101. }
  102.  
  103. void pixelize_shell::OpenDoc( Boolean opening)
  104. {
  105. //
  106. // WARNING: Ugly long function ahead!
  107. //
  108.     const OSType theType = theCInfoPBRec.hFileInfo.ioFlFndrInfo.fdType;
  109. //
  110. // read in the PICT:
  111. //
  112.     PicHandle thePICT = 0;
  113.  
  114.     switch( theType)
  115.     {
  116.         case 'PICT':
  117.             thePICT = ReadPictFile( thefsspec);
  118.             break;
  119.  
  120.         case 'pgm5':
  121.         case 'PGM5':
  122.             thePICT = Read_pgm_file( thefsspec);
  123.             break;
  124.  
  125.         default:
  126.             thePICT = ReadPictResource( thefsspec);
  127.     }
  128.     if( thePICT == 0)
  129.     {
  130.         SysBeep( 9);
  131.     } else {
  132.         Rect PICTRect = (**thePICT).picFrame;
  133.         OffsetRect( &PICTRect, -PICTRect.left, -PICTRect.top);
  134.         const short PICTWidth  = PICTRect.right;
  135.         const short PICTheight = PICTRect.bottom;
  136. //
  137. // Obtain a color table for the resulting PICT:
  138. //
  139.         CTabHandle theNewColorTable = 0L;
  140.  
  141.         const int requestedDepth = (1 << (whichDepth - 1));
  142.  
  143.         if( requestedDepth == 1)
  144.         {
  145.             theNewColorTable = (CTabHandle)GetResource( 'clut', 1);
  146.             DetachResource( (Handle)theNewColorTable);
  147.         } else {
  148.             switch( whichSampling)
  149.             {
  150.                 case useSystemDefault:
  151.                     //
  152.                     // do we need this or will the gworld get this one, anyway?
  153.                     //
  154.                     theNewColorTable = (CTabHandle)GetResource( 'clut', requestedDepth);
  155.                     DetachResource( (Handle)theNewColorTable);
  156.                     break;
  157.  
  158.                 default:
  159.                     //
  160.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  161.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  162.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  163.                     //
  164.                     //        user-specified selection in a resource. For now, we assume that
  165.                     //        user-specified resources are numbered consecutive with the
  166.                     //        system ones. THIS IS A BUG, since nothing is known about the order
  167.                     //        in which the items are added to the pop-up menu. I repeat:
  168.                     //
  169.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  170.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  171.                     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  172.                     //
  173.                 case useSystemMethod:
  174.                 case usePopularMethod:
  175.                 case useMedianMethod:
  176.                     const int real_method = systemMethod + (whichSampling - useSystemMethod);
  177.  
  178.                     const int requestedColors = (1 << requestedDepth)
  179.                             - (2 * alwaysAddBW);                            // for black and white
  180.                     //
  181.                     // convert the picture to a pixmap, if 'countPixels' is set.
  182.                     // This makes that the 'GetPictInfo' call will do a 'GetPixMapInfo' instead.
  183.                     // The default depth for the PixMap is 32. This eats a lot of memory, but
  184.                     // ensures a loss-free conversion.
  185.                     //
  186.                     if( countPixels)
  187.                     {
  188.                         PicHandle temp = thePICT;
  189.                         thePICT = convertToPixMap( temp);
  190.                         KillPicture( temp);
  191.                     }
  192.                     //
  193.                     // Obtain color table = Color matching requested => GetPictInfo,
  194.                     // else get color table from system.
  195.                     //
  196.                     // Obtain picture info:
  197.                     //
  198.                     const short version = 0;
  199.  
  200.                     PictInfo thePictInfo;
  201.  
  202.                     static const int theAsks[ 2] =
  203.                     {
  204.                         returnColorTable, returnPalette | suppressBlackAndWhite
  205.                     };
  206.                     const int toAsk = theAsks[ alwaysAddBW];
  207.  
  208.                     if( GetPictInfo( thePICT, &thePictInfo,
  209.                         toAsk, requestedColors, real_method, version) == noErr)
  210.                     {
  211.                         //
  212.                         // Build a color table with black and white added:
  213.                         //
  214.                         if( alwaysAddBW)
  215.                         {
  216.                             theNewColorTable = AddBlackWhite( thePictInfo.thePalette);
  217.  
  218.                             DisposeHandle( (Handle)thePictInfo.thePalette);
  219.                         } else {
  220.                             theNewColorTable = thePictInfo.theColorTable;
  221.                         }
  222.                     } else {
  223.                         SysBeep( 9);
  224.                     }
  225.                     break;
  226.             }
  227.         }
  228.         //
  229.         // create the pix map picture:
  230.         //
  231.         short mode = real_modes[ whichTransfermode - 1];
  232.         if( dither)
  233.         {
  234.             mode += ditherCopy;
  235.         }
  236.         PicHandle temp = thePICT;
  237.  
  238.         thePICT = convertToPixMap( temp, requestedDepth, theNewColorTable, makeTransparent, mode);
  239.         KillPicture( temp);
  240.         DisposeHandle( (Handle)theNewColorTable);
  241.         //
  242.         // write the resulting Picture to the file:
  243.         // (Note: the order of WritePictFile, WritePictResource is important;
  244.         // WritePictFile replaces the original files, WritePictResource updates it.
  245.         //
  246.         if( whichStorage != iPICTResource)
  247.         {
  248.             WritePictFile( thefsspec, thePICT);
  249.             (void)thefsspec.SetFType( 'PICT');
  250.         }
  251.         if( whichStorage != iPictFile)
  252.         {
  253.             WritePictResource( thefsspec, thePICT);
  254.         }
  255.         KillPicture( thePICT);
  256.     }
  257. }
  258.  
  259. void pixelize_shell::HandleDialogEvent( short itemHit, DialogPtr theDialog)
  260. {
  261.     switch( itemHit)
  262.     {
  263.         case iBlackAndWhite:
  264.         case i2Bits:
  265.         case i4Bits:
  266.         case i8Bits:
  267.             ChangeDepth( itemHit);
  268.             break;
  269.  
  270.         case iCountPixels:
  271.             countPixels = !countPixels;
  272.             SetAButton( iCountPixels, countPixels);
  273.             break;
  274.  
  275.         case iAlwaysAddBW:
  276.             alwaysAddBW = !alwaysAddBW;
  277.             SetAButton( iAlwaysAddBW, alwaysAddBW);
  278.             break;
  279.  
  280.         case iCLUTSelection:
  281.             {
  282.                 short    iType;
  283.                 Handle    iHandle;
  284.                 Rect    iRect;
  285.                 GetDialogItem( gMainDialog, iCLUTSelection, &iType, &iHandle, &iRect);
  286.                 whichSampling = GetControlValue( (ControlHandle)iHandle);
  287.                 ChangeSampling( whichSampling);        // slight overkill, sets control value
  288.             }
  289.             break;
  290.  
  291.         case iTransparent:
  292.             makeTransparent = !makeTransparent;
  293.             SetAButton( iTransparent, makeTransparent);
  294.             break;
  295.  
  296.         case iDither:
  297.             dither = !dither;
  298.             SetAButton( iDither, dither);
  299.             break;
  300.  
  301.         case iTransferMode:
  302.             {
  303.                 short    iType;
  304.                 Handle    iHandle;
  305.                 Rect    iRect;
  306.                 GetDialogItem( gMainDialog, iTransferMode, &iType, &iHandle, &iRect);
  307.                 whichTransfermode = GetControlValue( (ControlHandle)iHandle);
  308.             }
  309.             break;
  310.  
  311.         case iPictFile:
  312.         case iPICTResource:
  313.         case iBoth:
  314.             ChangeStorage( itemHit);
  315.             break;
  316.     }
  317. }
  318.  
  319. void pixelize_shell::ChangeDepth( int newDepth)
  320. {
  321.     SetOnlyOne( iBlackAndWhite, i8Bits, newDepth);
  322.     whichDepth = newDepth;
  323. }
  324.  
  325. void pixelize_shell::ChangeStorage( int newStorage)
  326. {
  327.     SetOnlyOne( iPictFile, iBoth, newStorage);
  328.     whichStorage = newStorage;
  329. }
  330.  
  331. void pixelize_shell::ChangeSampling( int newSampling)
  332. {
  333.     short    iType;
  334.     Handle    iHandle;
  335.     Rect    iRect;
  336.     GetDialogItem( gMainDialog, iCLUTSelection, &iType, &iHandle, &iRect);
  337.     SetControlValue( (ControlHandle)iHandle, newSampling);
  338.  
  339.     whichSampling = newSampling;
  340.  
  341.     const int theHilite = (whichSampling == useSystemDefault) ? 255 : 0;
  342.  
  343.     GetDialogItem( gMainDialog, iCountPixels, &iType, &iHandle, &iRect);
  344.     HiliteControl( (ControlHandle)iHandle, theHilite);
  345.  
  346.     GetDialogItem( gMainDialog, iAlwaysAddBW, &iType, &iHandle, &iRect);
  347.     HiliteControl( (ControlHandle)iHandle, theHilite);
  348. }
  349.  
  350. void pixelize_shell::ChangeMode( int newTransfermode)
  351. {
  352.     short    iType;
  353.     Handle    iHandle;
  354.     Rect    iRect;
  355.     GetDialogItem( gMainDialog, iTransferMode, &iType, &iHandle, &iRect);
  356.     SetControlValue( (ControlHandle)iHandle, newTransfermode);
  357.  
  358.     whichTransfermode = newTransfermode;
  359. }
  360.  
  361. void pixelize_shell::SetAButton( short theItem, Boolean theValue) const
  362. {
  363.     short    iType;
  364.     Handle    iHandle;
  365.     Rect    iRect;
  366.     GetDialogItem( gMainDialog, theItem, &iType, &iHandle, &iRect);
  367.     SetControlValue( (ControlHandle)iHandle, theValue);
  368. }
  369.  
  370. void pixelize_shell::SetOnlyOne( short firstItem, short lastItem, short ItemToSet)
  371. {
  372.     short    iType;
  373.     Handle    iHandle;
  374.     Rect    iRect;
  375.  
  376.     for( int i = firstItem; i <= lastItem; i++)
  377.     {
  378.         GetDialogItem( gMainDialog, i, &iType, &iHandle, &iRect);
  379.         SetControlValue( (ControlHandle)iHandle, (i == ItemToSet));
  380.     }
  381. }
  382.  
  383. PicHandle pixelize_shell::ReadPictFile( const fsspec &thefsspec) const
  384. {
  385.     PicHandle result = 0;
  386.     access_path thefile( thefsspec, fsRdPerm);
  387.  
  388.     OSErr err = thefile();
  389.  
  390.     long picture_size = 0;
  391.     err = thefile.GetEOF( &picture_size);
  392.  
  393.     picture_size -= 0x0200;
  394.  
  395.     err = thefile.SetFPos( 0x0200);
  396.  
  397.     if( err == noErr)
  398.     {
  399.         result = (PicHandle)NewHandle( picture_size);
  400.         HLock( (Handle)result);
  401.             err = thefile.Read( &picture_size, (char *)*result);
  402.         HUnlock( (Handle)result);
  403.         if( err != noErr)
  404.         {
  405.             DisposeHandle( (Handle)result);
  406.             result = 0;
  407.         }
  408.     }
  409.     err = thefile.Close();
  410.  
  411.     return result;
  412. }
  413.  
  414. PicHandle pixelize_shell::ReadPictResource( const fsspec &thefsspec) const
  415. {
  416.     PicHandle result = 0;
  417.     resourcefile thefile( thefsspec);
  418.  
  419.     OSErr err = thefile.Open( fsRdPerm);
  420.  
  421.     if( err == noErr)
  422.     {
  423.         result = (PicHandle)Get1IndResource( 'PICT', 1);
  424.         DetachResource( (Handle) result);
  425.     }
  426.     err = thefile.Close();
  427.  
  428.     return result;
  429. }
  430.  
  431. PicHandle pixelize_shell::Read_pgm_file( const fsspec &thefsspec) const
  432. {
  433.     PicHandle result = 0;
  434.     access_path thefile( thefsspec, fsRdPerm);
  435.  
  436.     OSErr err = thefile();
  437.  
  438.     if( err == noErr)
  439.     {
  440.         #define maxLength 200
  441.         typedef struct pgm
  442.         {
  443.             short P5;
  444.             char firstLine[ maxLength];
  445.         } pgm;
  446.         struct pgm thePGM;
  447.         long count = sizeof( pgm);
  448.         err = thefile.Read( &count, &thePGM);
  449.  
  450.         if( (err == noErr) && (thePGM.P5 == 'P5'))
  451.         {
  452.             //
  453.             // Read the fields Xres, Yres, max value:
  454.             //
  455.             istrstream in( thePGM.firstLine, maxLength);
  456.  
  457.             short maxX;
  458.             short maxY;
  459.             short maxVal;
  460.  
  461.             in >> maxX >> maxY >> maxVal;
  462.             //
  463.             // Find the line break:
  464.             //
  465.             for( int i = 0; i < maxLength; i++)
  466.             {
  467.                 const char c = thePGM.firstLine[ i];
  468.  
  469.                 if( (c == '¥n') || (c == '¥r'))
  470.                 {
  471.                     break;
  472.                 }
  473.             }
  474.             err = thefile.SetFPos( i + 1 + 2);        // 1 for '¥n', 2 for 'P5'
  475.  
  476.             CTabHandle grays = (CTabHandle)Get1Resource( 'clut', 129);
  477.             gworld offscreen( maxX, maxY, 8, true, grays);
  478.             //
  479.             // Stuff the binary data in the offscreen bitmap
  480.             //
  481.             PixMapPtr thePix = offscreen.get_pixH();
  482.  
  483.             Ptr baseAddr = thePix->baseAddr;
  484.             const short rowBytes = (thePix->rowBytes) & (~0xC000);
  485.             //
  486.             // Read in the binary data:
  487.             //
  488.             for( int y = 0; (y < maxY) && (err == noErr); y++)
  489.             {
  490.                 long numtoRead = maxX;
  491.                 err = thefile.Read( &numtoRead, baseAddr);
  492.                 baseAddr += rowBytes;
  493.             }
  494.             //
  495.             // LockPixels( thePix); not needed; gworld does this
  496.             //
  497.             // Convert the thing to a picture:
  498.             //
  499.             result = offscreen.makePICT();
  500.         }
  501.     }
  502.     err = thefile.Close();
  503.  
  504.     return result;
  505. }
  506.  
  507. CTabHandle pixelize_shell::AddBlackWhite( const PaletteHandle thePalette) const
  508. {
  509.     const int numToAdd = (**thePalette).pmEntries;
  510.     //
  511.     // Build a color table with black and white added:
  512.     //
  513.     PaletteHandle newPalette = GetNewPalette( 128);    // contains black and white
  514.  
  515.     ResizePalette( newPalette, numToAdd + 2);
  516.     CopyPalette( thePalette, newPalette, 1, 3, numToAdd);
  517.  
  518.     CTabHandle result = (CTabHandle)Get1Resource( 'clut', 128);
  519.     DetachResource( (Handle)result);
  520.  
  521.     Palette2CTab( thePalette, result);
  522.     DisposeHandle( (Handle)newPalette);
  523.     return result;
  524. }
  525.  
  526. PicHandle pixelize_shell::convertToPixMap(
  527.     const PicHandle thePICT, short bitDepth,
  528.     const CTabHandle theColorTable, Boolean transparent, short mode) const
  529. {
  530.     Rect PICTRect = (**thePICT).picFrame;
  531.     OffsetRect( &PICTRect, -PICTRect.left, -PICTRect.top);
  532.  
  533.     const short PICTWidth  = PICTRect.right;
  534.     const short PICTheight = PICTRect.bottom;
  535.     //
  536.     // convert the picture to a (large) picture containing only a pixmap
  537.     //
  538.     gworld offscreen( PICTWidth, PICTheight, bitDepth, true, theColorTable);
  539.     offscreen.Set();
  540.     DrawPicture( thePICT, &PICTRect);
  541.  
  542.     PicHandle result = 0L;
  543.  
  544.     if( transparent)
  545.     {
  546.         gworld mask( PICTWidth, PICTheight, 1);
  547.         mask.Set();
  548.         DrawPicture( thePICT, &PICTRect);
  549.         RgnHandle maskRegion = mask.makeRegion();
  550.         result = offscreen.makePICT( mode, maskRegion);
  551.         DisposeRgn( maskRegion);
  552.     } else {
  553.         result = offscreen.makePICT( mode);
  554.     }
  555.     return result;
  556. }
  557.  
  558. void pixelize_shell::WritePictFile( const fsspec &thefsspec, const PicHandle thePICT) const
  559. {
  560.     OSErr err = noErr;
  561.     //
  562.     // Write a PICT Header first:
  563.     // (to be safe, we write to a temporary file)
  564.     //
  565.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  566.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  567.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  568.     //
  569.     //        We use a nice fail-safe strategy here. Unfortunately I don't know
  570.     //        whether that fail-safe strategy will work when the original file is not
  571.     //        on the boot volume. Do all volumes have a private temporary items folder?
  572.     //
  573.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  574.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  575.     // BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT! BUG ALERT!
  576.     //
  577.     fsspec tempFile( kTemporaryFolderType, "¥pPixelize temp" , thefsspec.vRefNum);
  578.  
  579.     tempFile.CreateUnique( 'ttxt', 'PICT');
  580.  
  581.     access_path tempAcess( tempFile, fsWrPerm);
  582.     err = tempAcess();
  583.  
  584.     long FiveOneTwo = 0x0200;
  585.     Ptr header = NewPtrClear( FiveOneTwo);
  586.     err = tempAcess.SetFPos( 0x0000);
  587.  
  588.     err = tempAcess.Write( &FiveOneTwo, header);
  589.  
  590.     DisposePtr( header);
  591.  
  592.     if( err == noErr)
  593.     {
  594.         //
  595.         // Then write the PICT itself:
  596.         //
  597.         long new_size = GetHandleSize( (Handle)thePICT);
  598.         err = tempAcess.SetEOF( new_size + FiveOneTwo);
  599.         err = tempAcess.SetFPos( FiveOneTwo);
  600.  
  601.         if( err == noErr)
  602.         {
  603.             HLock( (Handle)thePICT);
  604.                 err = tempAcess.Write( &new_size, *(Handle)thePICT);
  605.             HUnlock( (Handle)thePICT);
  606.         }
  607.         if( err == noErr)
  608.         {
  609.             err = tempAcess.Close();
  610.             if( err == noErr)
  611.             {
  612.                 err = tempFile.ExchangeFiles( thefsspec);
  613.             }
  614.         }
  615.     }
  616.     tempFile.Delete();
  617. }
  618.  
  619. void pixelize_shell::WritePictResource( const fsspec &thefsspec, const PicHandle thePICT) const
  620. {
  621.     resourcefile thefile( thefsspec);
  622.     OSErr err = thefile.Create();
  623.     err = thefile.Open( fsRdWrPerm);
  624.     err = thefile.Use();
  625.     if( err == noErr)
  626.     {
  627.         AddResource( (Handle)thePICT, 'PICT', UniqueID( 'PICT'), "¥pConverted PICT");
  628.         err = ResError();
  629.         err = thefile.Update();
  630.         DetachResource( (Handle)thePICT);
  631.         err = thefile.Close();
  632.     }
  633. }
  634.